/***************************************************************************
 *   Copyright (C) 2010 by Oleg Goncharov  *
 *   $EMAIL$                           *                          
 *                                                                         *
 *   This file is part of ChessVision.                                     *
 *                                                                         *
 *   ChessVision is free software; you can redistribute it and/or modify   *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <opencv/cv.h>

#include "vision/cimagecamera.h"
#include "vision/cpointmaxcolor.h"
#include "vision/ccamtransform.h"
#include "vision/cpointcirclecenter.h"
#include "vision/cpointmatch.h"
#include "vision/cpointbackhist.h"
#include "vision/cimagecamthread.h"
#include "vision/cimagefromfile.h"

#include "katanavision/ckatanawitheye.h"
#include "katanavision/katanafuncs.h"

#include "choughdetector.h"
#include "ccornerdetector.h"
#include "chtransdetector.h"

#include "cnormbayerfigures.h"
#include "cfigureboosting.h"
#include "cfiguresvm.h"
#include "ckmeanfigure.h"

#include "cgnuchessenvelop.h"

#include "cchessmaster.h"
#include "chesserror.h"

using namespace std;
using namespace Chess;
using namespace Katana;

void TrainFigureDetector(IplImage * img, const CBoardCells& _cells, CFigureFeature& df) {	
	CBoardCells cells(_cells);
	cells.Rotate(df.InitialPositionAngle(img, cells));
	df.TrainSample(img, cells, CPosition(true));
	CPosition pos;
	
	cv::Mat result(img, true);
	df.DetectFigures(img, cells, pos);
	pos.DrawPosition(result, cells);
	cv::namedWindow("Train", 1);
	cv::imshow("Train", result);
	cv::waitKey(1000);
}
	
int main( int argc, char *argv[] )
{	
	try {
		TCdlCOMDesc ccd = {0, 57600, 8, 'N', 1, 300, 0};
		CCdlCOM device(ccd);
		CCplSerialCRC protocol;
		protocol.init(&device);
		Katana::CKatanaSensing katana;
		katana.create ( "katana5M180.cfg", &protocol );
		katana.moveRobotTo(0, 400, 0, 0,0,0, true);
		
		//CImageCamera cam(0);
		//CImageDvGrab cam("--jpeg-quality 100");
		CImageCamThread cam(0, 50);
		//CImageFromFile cam("../../imgs/idealrotf.png");
		
		IplImage * endarm_sample = cvLoadImage("pattern.jpg");
		if (!endarm_sample) throw Errors::CError("No pattern");
		CPointScaleMatch endarm(endarm_sample, 0.5, 2.0, 4, CPointNorm::NO_NORM);
		
		CCamTransform camtr("calibdata.xml");
		camtr.LoadTransform("transform.xml");
		
		Katana::CKatanaWithEye arm(katana, cam, endarm, camtr);
		
		CHTransDetector det;
		det.SetCannyThereholds(30,70);
		//CHoughDetector det;
		//det.SetStep_h(1);
		//det.SetStep_teta(0.05);
		det.SetSteps(0.7f, 0.01f);
		//CFigureKMean fig("R4A G4A B4A R6A G6A B6A R7A G7A B7A M4A M7A", CFigureKMean::MEDIUM,  8, 20);
		CFigureBoosting fig("R4A G4A B4A R6A G6A B6A R7A G7A B7A M4A M7A", 0);
		//CFigureSVM fig("R4A G4A B4A R6A G6A B6A R7A G7A B7A M4A M7A", 0);
		
		cout << "Wait fo camera." << endl;
		
		cvNamedWindow("camera", 0);
		for(int i = 0; i < 20; i++) {
			cv::imshow("camera", cam.GrabFrame());
			cv::waitKey(500);
		}
		cvDestroyWindow("camera");
		
		CBoardCells cells;
		for (int i = 0; i < 3; i++) {
			do {
				cam.GrabFrame();
				cout << "Detecting chessboard ... " << endl;
			} while (!det.DetectChessboard(cam.Img(), cells));
			cout << "done." << endl  << "Train FigureDetector." << endl;
			TrainFigureDetector(cam.Img(), cells, fig);
		}
		
		CGnuchessEnvelop engine("/usr/games/hoichess");
		
		CChessMaster master(arm, det, fig, engine);
		
		int attempts;
		cout << "Start game." << endl;
		//getchar();
		attempts = 3;
		while (1) {
			//attempts = 1000;
			getchar();
			
			do {
				try {
					while (!master.HumanMove()) {}
				} 
				catch (Errors::CHumanMoveError& e) {
					e.Report();
					cout << "Minimum " << e.GetMinDiff() << " differences." << endl;
					cout << "Hit any key to train." << endl;
					cv::Mat result = master.Image().clone();
					master.RecognPosition().DrawPosition(result, master.RecognBoard());
					cv::imshow("Train", result);
					if (-1 != cv::waitKey(1000)) {
						cout << "Retrain ... ";
						fig.TrainSample(master.Image(), master.RecognBoard(), master.Position());	
						cout << "done." << endl;
					}
					continue;
				} catch (Errors::CWeakError& e) {
					cout << "WeakError have occured. Board or figures are not detected. Next attempt." << endl;
					continue;
				}
				break;
			} while (1);
		
			do {
				try {
					master.ComputerMove();	
				}
				catch ( MotorOutOfRangeException& e ) {
					if (!attempts--) throw;
					cout  << e.message() << endl;
					cout  << "Try to adjust chessboard." << std::endl;
					continue;
				}
				break;
			} while (1);
		}
		cout << "End game." << endl;
		
	} 
	catch ( Exception &e ) {
		std::cout << "ERROR: " << e.message() << std::endl;
		return -1;
	}
	catch ( Errors::CError& e ) {
		e.Report(std::cout);		
	}
}




